package com.tarena.lbs.coupon.rpc;

import com.tarena.lbs.base.protocol.exception.BusinessException;
 import com.tarena.lbs.base.protocol.pager.PageResult;
import com.tarena.lbs.coupon.api.CouponApi;
import com.tarena.lbs.coupon.api.pojo.param.UserCouponsParam;
import com.tarena.lbs.coupon.dao.repository.CouponRepository;
import com.tarena.lbs.coupon.dao.repository.UserCouponsRepository;
import com.tarena.lbs.coupon.enums.StockResultEnum;
import com.tarena.lbs.coupon.pojo.po.CouponPO;
import com.tarena.lbs.coupon.pojo.po.UserCouponsPO;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @Author: goodman
 * @Date: 2025/5/15 17:31
 */

@Slf4j
@Component
@DubboService
public class CouponApiImpl implements CouponApi {

    @Autowired
    private CouponRepository couponRepository;
    
    @Autowired
    private UserCouponsRepository userCouponsRepository;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public void receiveCoupon(UserCouponsParam param) throws BusinessException {
        log.info("用户领取优惠券: {}", param);
        
        // 1. 参数校验
        if (param == null) {
            throw new BusinessException(StockResultEnum.DATA_NOT_FIND);
        }
        if (param.getUserId() == null) {
            throw new BusinessException(StockResultEnum.USER_ID_NULL);
        }
        if (param.getCouponId() == null) {
            throw new BusinessException(StockResultEnum.COUPON_ID_NULL);
        }
        
        // 2. 检查优惠券是否存在
        CouponPO couponPO = couponRepository.selectById(param.getCouponId());
        if (couponPO == null) {
            throw new BusinessException(StockResultEnum.COUPON_NOT_FIND);
        }
        
        // 3. 检查优惠券状态是否有效
        if (couponPO.getStatus() != 1 || couponPO.getEnableStatus() != 1) {
            throw new BusinessException(StockResultEnum.COUPON_INVALID);
        }
        
        // 4. 检查优惠券时间是否在有效期内
        Date now = new Date();
        log.debug("检查优惠券时间: 优惠券ID={}, 当前时间={}, 开始时间={}, 结束时间={}", 
                 param.getCouponId(), now, couponPO.getStartDate(), couponPO.getEndDate());
        
        if (couponPO.getStartDate() != null && now.before(couponPO.getStartDate())) {
            log.warn("优惠券尚未开始: 当前时间{}早于开始时间{}", now, couponPO.getStartDate());
            throw new BusinessException(StockResultEnum.COUPON_TIME_INVALID);
        }
        
        if (couponPO.getEndDate() != null && now.after(couponPO.getEndDate())) {
            log.warn("优惠券已过期: 当前时间{}晚于结束时间{}", now, couponPO.getEndDate());
            throw new BusinessException(StockResultEnum.COUPON_TIME_INVALID);
        }
        
        // 5. 检查用户是否已经领取过该优惠券
        int count = userCouponsRepository.countByUserIdAndCouponId(param.getUserId(), param.getCouponId());
        if (count > 0) {
            throw new BusinessException(StockResultEnum.COUPON_ALREADY_RECEIVED);
        }
        
        // 6. 使用Redis检查并扣减库存
        String stockKey = "coupon:stock:" + param.getCouponId();
        Object stockObj = redisTemplate.opsForValue().get(stockKey);
        Integer stock = null;
        
        if (stockObj != null) {
            stock = Integer.valueOf(stockObj.toString());
        } else {
            // 如果Redis中没有库存信息，从数据库查询
            // 注意：这里简化处理，实际应该有查询优惠券库存的方法
            // 此处假设优惠券的maxUsageLimit就是总库存
            stock = couponPO.getMaxUsageLimit();
            if (stock != null) {
                redisTemplate.opsForValue().set(stockKey, stock, 24, TimeUnit.HOURS);
            }
        }
        
        if (stock != null && stock <= 0) {
            throw new BusinessException(StockResultEnum.COUPON_STOCK_EMPTY);
        }
        
        // 7. 扣减库存
        Long decrementResult = redisTemplate.opsForValue().decrement(stockKey);
        if (decrementResult == null || decrementResult < 0) {
            // 库存不足，回滚
            redisTemplate.opsForValue().increment(stockKey);
            throw new BusinessException(StockResultEnum.COUPON_STOCK_EMPTY);
        }
        
        try {
            // 8. 生成优惠券码
            String couponCode = generateCouponCode();
            
            // 9. 保存用户优惠券信息
            UserCouponsPO userCouponsPO = new UserCouponsPO();
            BeanUtils.copyProperties(param, userCouponsPO);
            userCouponsPO.setStatus(0); // 0表示未使用
            userCouponsPO.setCreateAt(now);
            userCouponsPO.setUpdateAt(now);
            userCouponsPO.setCouponCode(couponCode);
            userCouponsPO.setCouponType(couponPO.getCouponType());
            userCouponsPO.setCouponValue(couponPO.getDiscountValue());
            
            // 如果参数中没有活动ID和店铺ID，从优惠券中获取
            if (userCouponsPO.getActivityId() == null) {
                // 假设优惠券和活动有关联，这里简化处理
                userCouponsPO.setActivityId(1); // 默认为1，实际应该从优惠券或参数中获取
            }
            if (userCouponsPO.getShopId() == null) {
                // 假设从商家ID关联获取店铺ID，这里简化处理
                userCouponsPO.setShopId(1); // 默认为1，实际应该从商家信息中获取
            }
            
            int insertResult = userCouponsRepository.insert(userCouponsPO);
            if (insertResult <= 0) {
                throw new BusinessException(StockResultEnum.COUPON_RECEIVE_FAIL);
            }
            
            log.info("用户领取优惠券成功: 用户ID={}, 优惠券ID={}, 优惠券码={}", 
                     param.getUserId(), param.getCouponId(), couponCode);
        } catch (Exception e) {
            // 发生异常，回滚库存
            redisTemplate.opsForValue().increment(stockKey);
            log.error("用户领取优惠券失败: {}", e.getMessage(), e);
            throw new BusinessException(StockResultEnum.COUPON_RECEIVE_FAIL);
        }
    }
    
    /**
     * 生成优惠券码
     * @return 优惠券码
     */
    private String generateCouponCode() {
        // 使用UUID生成唯一的优惠券码
        return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16).toUpperCase();
    }
}